package top.xana.acg.anime.ui.viewmodel

import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope
import com.skydoves.bindables.BindingViewModel
import com.skydoves.bindables.asBindingProperty
import com.skydoves.bindables.bindingProperty
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import top.xana.acg.anime.SearchSource
import top.xana.acg.anime.model.*
import top.xana.acg.anime.repo.AnimeRepo
import top.xana.acg.common.utils.CalendarUtils
import top.xana.acg.anime.utils.LogE
import javax.inject.Inject

/**
 * @author xana
 * @date 2022/10/30 0030 11:55
 * @email cv4096@qq.com
 **/

@HiltViewModel
class AnimeViewModel @Inject constructor(val repo: AnimeRepo) : BindingViewModel() {
    companion object {
        const val TAG = "AnimeViewModel"

        private const val PAGE_SIZE = 15
        private const val INIT_LOAD_SIZE = 15

    }

    @get:Bindable
    val homeUiData: List<Any> by loadPageUiDate().asBindingProperty(viewModelScope, listOf())

    @get:Bindable
    @set:Bindable
    var currentPlayingAnime: Anime? by bindingProperty(null)

    init {
        loadPageUiDate()
    }

    private fun loadPageUiDate() = combine(
        repo.loadBanner(),
        repo.loadCollection(),
        repo.loadHot(),
        repo.loadTimeline(),
        repo.loadHomeBody()
    ) { bannerList, collection, hotAnime, timeline, homeBody ->
        val list = mutableListOf<Any>()
        list.add(BannerUi(bannerList))
        list.add(LabelUi(LabelUi.TITLE_MY_SUBSCRIBE, LabelUi.EXT_MORE))
        list.add(CollectionUi(collection))
        list.add(LabelUi(LabelUi.TITLE_HOT_LIVING, LabelUi.EXT_MORE))
        list.addAll(hotAnime)
        list.add(LabelUi(LabelUi.TITLE_TIMELINE, LabelUi.EXT_MORE))
        val weekIndex = if (CalendarUtils.weekday > 0) CalendarUtils.weekday - 1 else 6
        for (e in timeline[weekIndex]) {
            e.src = Anime.SOURCE_TIMELINE
        }
        list.addAll(timeline[weekIndex].take(5))
        for (body in homeBody) {
            list.add(LabelUi(body.label, LabelUi.EXT_MORE))
            list.addAll(body.items)
        }
        list
    }.catch {
        LogE("catch... when loading homepage", t = it, tag = TAG)
    }.onEach {
        LogE("fetch... $it", TAG)
    }

    suspend fun loadTimeline() = repo.loadTimeline()

    fun search(
        searchSource: SearchSource,
        keyword: String,
        page: Int,
        callback: (List<Anime>) -> Unit
    ) = repo.search(searchSource, keyword, page)
        .catch { LogE("catch... when searching", t = it, tag = TAG) }
        .onEach { callback.invoke(it) }
        .flowOn(Dispatchers.Main)
        .launchIn(viewModelScope)


    fun loadHomeCate(i: Int, page: Int, callback: (List<Anime>) -> Unit) =
        repo.loadHomeCate(i, page)
            .catch { LogE("catch... when loading category", t = it, tag = TAG) }
            .onEach { callback.invoke(it) }
            .flowOn(Dispatchers.Main)
            .launchIn(viewModelScope)

    fun loadSource(searchSource: SearchSource, uri: String, callback: (List<SourceUi>) -> Unit) =
        repo.loadSource(searchSource, uri)
            .catch { LogE("catch... when loading source", t = it, tag = TAG) }
            .onEach { src ->
                val sourceUis = src.mapIndexed { i, eps ->
                    SourceUi(title = "资源线路${i + 1}", episodes = eps)
                }
                callback.invoke(sourceUis)
            }.launchIn(viewModelScope)

    fun loadAnimeDetail(searchSource: SearchSource, uri: String, callback: (Anime) -> Unit) =
        repo.loadDetail(searchSource, uri)
            .catch { LogE("catch... when loading detail", t = it, tag = TAG) }
            .onEach { callback.invoke(it) }
            .flowOn(Dispatchers.Main)
            .launchIn(viewModelScope)

    fun loadRelated(searchSource: SearchSource, uri: String, callback: (List<Anime>) -> Unit) =
        repo.loadFavor(searchSource, uri)
            .catch { LogE("catch... when loading related", t = it, tag = TAG) }
            .onEach { callback.invoke(it) }
            .flowOn(Dispatchers.Main)
            .launchIn(viewModelScope)

    fun loadPlayUrl(
        searchSource: SearchSource,
        title: String,
        uri: String,
        callback: (String, String) -> Unit
    ) = repo.loadPlayUrl(searchSource, uri)
        .catch { LogE("catch... when loading playUrl", t = it, tag = TAG) }
        .onEach { callback.invoke(title, it) }
        .flowOn(Dispatchers.Main)
        .launchIn(viewModelScope)

}